package com.cjf.aop.runtime.aspectj;

import android.text.TextUtils;

import com.cjf.aop.annotation.CaptureThrowable;
import com.cjf.aop.runtime.AOPManager;
import com.cjf.aop.runtime.logger.XLogger;
import com.cjf.aop.runtime.utils.Utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 自动try-catch的注解切片处理
 * created by cjf
 * on: 2020/3/25
 */
@Aspect
public class CaptureThrowableAspectJ {

    /**
     * 带 {@link com.cjf.aop.annotation.CaptureThrowable} 注解的所有类
     */
    @Pointcut("within(@com.cjf.aop.annotation.CaptureThrowable *)")
    public void withinAnnotatedClass() {
    }

    /**
     * 带 {@link com.cjf.aop.annotation.CaptureThrowable} 注解的所有类，除去synthetic 修饰的方法
     */
    @Pointcut("execution(!synthetic * *(..)) && withinAnnotatedClass()")
    public void methodInsideAnnotatedType() {
    }

    /**
     * 带 {@link com.cjf.aop.annotation.CaptureThrowable} 注解的所有类，c除去synthetic修饰的构造方法
     */
    @Pointcut("execution(!synthetic *.new(..)) && withinAnnotatedClass()")
    public void constructorInsideAnnotationType() {
    }

    /**
     * 方法切入点，带有 {@link com.cjf.aop.annotation.CaptureThrowable} 注解的方法,或者带有@DebugLog注解的类并除去synthetic修饰的方法
     */
    @Pointcut("execution(@com.cjf.aop.annotation.CaptureThrowable * *(..)) || methodInsideAnnotatedType()")
    public void method() {
    }

    /**
     * 构造器切入点，带有 {@link com.cjf.aop.annotation.CaptureThrowable} 注解的构造方法,或者带有@DebugLog注解的类并除去synthetic修饰的构造方法
     */
    @Pointcut("execution(@com.cjf.aop.annotation.CaptureThrowable *.new(..)) || methodInsideAnnotatedType()")
    public void constructor() {
    }


    /**
     * 定义Advice,使用了@annotation(captureThrowable)这种方法来告诉 AspectJ，这个 captureThrowable 是一个注解
     *
     * @param joinPoint        程序运行时的一些 执行点
     * @param captureThrowable 异常注解
     */
    @Around("(method() || constructor()) && @annotation(captureThrowable)")
    public Object aroundJoinPoint(ProceedingJoinPoint joinPoint, CaptureThrowable captureThrowable) {
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            if (AOPManager.getInstance().getThrowableHandler() != null) {
                String flag = captureThrowable.value();
                if (TextUtils.isEmpty(flag)) {
                    flag = Utils.getMethodName(joinPoint);
                }
                result = AOPManager.getInstance().getThrowableHandler().handleThrowable(flag, e);
            } else {
                XLogger.e(e); //默认不做任何处理
            }
        }
        return result;
    }
}
